﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace AutoUI
{
    /// <summary>
    /// 这是一个仪表盘控件
    /// </summary>
    [Designer(typeof(MetroDesigner)), Description("这是一个仪表盘控件")]
    [DefaultProperty("Value")]
    public partial class 仪表盘 : Control
    {
        #region Fields

        /// <summary>
        /// 一度°等于多少单位
        /// </summary>
        public float DegreesPerUnit;

        /// <summary>
        /// 这在设计指针
        /// </summary>
        public bool DesignerNeedle;

        /// <summary>
        /// 表盘结束的角度
        /// </summary>
        public float EndAngle;

        /// <summary>
        /// 指针角度(Value,Start,Sweep等变化的时候,会跟着变化),以0-360的方式表示
        /// </summary>
        public float NeedleAngle;

        /// <summary>
        /// 绘制文字的位置
        /// </summary>
        public PointF Position_Value = new PointF(0, 0);

        internal bool DesignerDescription;
        private float _max = 100;
        private float _min = 0;
        private float _StartAngle = 330;
        private float _SweepAngle = 240;
        private float _value = 10;

        private byte currentDecimalPlaces = 2;
        private Color currentValueColor = Color.Red;
        private string description = "仪表";
        private Color descriptionColor = Color.Black;
        private Font descriptionFont = new Font("宋体", 9);
        private PointF descriptionPoint = new PointF(0.5f, 0.8f);
        private float hightAlarm = 90;

        private float lowAlarm = 60;

        private Color mainTickColor = Color.Black;

        private int mainTickcount = 10;

        private float mainTickLegth = 0.15f;

        private GraphicsPath mainTickPath = new GraphicsPath();

        private int mainTickWidth = 3;

        private PointF meterPosition = new PointF(0.5f, 0.5f);

        private float meterRadius = 1.0f;

        private Color needleColor = Color.Green;

        private float needleHight = 0.05f;

        /// <summary>
        /// 指针路径
        /// </summary>
        private GraphicsPath NeedlePath = new GraphicsPath();

        private EnumStytle needleStytle = EnumStytle.Stytle2;

        private float needleWidth = 0.5f;

        private Pen pen = new Pen(Color.Red);

        /// <summary>
        /// 仪表的中心点,很重要,仪表都所有定位都依靠这个
        /// </summary>
        private PointF point_Center;

        /// <summary>
        /// 最大半径
        /// </summary>
        private float radius;

        private Color secondTickColor = Color.Black;

        private int secondTickcount = 2;

        private float secondTickLegth = 0.1f;

        private GraphicsPath secondTickPath = new GraphicsPath();

        private int secondTickWidth = 2;

        private Color thirdTickColor = Color.Black;

        private int thirdTickcount = 5;

        private float thirdTickLegth = 0.05f;

        private GraphicsPath thirdTickPath;

        private int thirdTickWidth = 1;
        private int tickNumberDecimalPointCount = 1;

        private bool tickNumberDirection;

        private Font tickNumberFont = new Font("宋体", 9);

        /// <summary>
        /// 数字刻度路径
        /// </summary>
        private GraphicsPath tickNumberPath = new GraphicsPath();

        private float tickNumberSize = 0.65f;

        private Color tickNumColor = Color.Black;
        private Color tickRingAlarmColor = Color.Orange;

        private Color tickRingColor = Color.Black;

        private Color tickRingErrorColor = Color.Red;

        private bool tickRingLegth = true;

        private GraphicsPath tickRingPath = new GraphicsPath();

        private int tickRingWidth = 2;

        private float tickSize = 0.95f;

        private string unit = "";

        /// <summary>
        ///一个单位等于多少度°
        /// </summary>
        private float unitPerDegrees;

        private Font valueFont = new Font("宋体", 12);

        /// <summary>
        /// Value路径
        /// </summary>
        private GraphicsPath ValuePath = new GraphicsPath();

        /// <summary>
        /// 绘制文字的位置当对于中点的偏移
        /// </summary>
        private PointF valuePositionOffset = new PointF(0.5f, 0.7f);

        private GraphicsPath descriotionPath = new GraphicsPath();

        #endregion Fields

        #region Constructors

        public 仪表盘()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SweepAngle = 240;
            this.Value = 20;
            this.Min = 0;
            this.Max = 100;
            this.StartAngle = 330;
            Init();
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        /// 当前值保留几位小数
        /// </summary>
        [Category("5.当前值显示设置"), Description("保留几位小数"), DisplayName("保留几位小数")]
        public byte CurrentDecimalPlaces
        {
            get { return currentDecimalPlaces; }
            set { currentDecimalPlaces = value; Init(); Invalidate(); }
        }

        /// <summary>
        ///当前值的颜色
        /// </summary>
        [Category("5.当前值显示设置"), Description("当前值的颜色"), DisplayName("当前值的颜色")]
        public Color CurrentValueColor
        {
            get { return currentValueColor; }
            set { currentValueColor = value; Invalidate(); }
        }

        /// <summary>
        /// 描述文字
        /// </summary>
        [Category("6.描述文字显示设置"), Description("描述文字"), DisplayName("描述文字")]
        public string Description
        {
            get { return description; }
            set
            {
                description = value;
                if (value != null && value != string.Empty)
                {
                    descriotionPath = new GraphicsPath();
                    descriotionPath.AddString(description, descriptionFont.FontFamily, (int)descriptionFont.Style, (Radius * descriptionFont.Size) / 60, new PointF(Width * descriptionPoint.X, Height * descriptionPoint.Y), SysConst.StringFormat_Center);
                    Invalidate();
                }
            }
        }

        /// <summary>
        /// 描述字体
        /// </summary>
        [Category("6.描述文字显示设置"), Description("描述字体颜色"), DisplayName("字体颜色")]
        public Color DescriptionColor
        {
            get { return descriptionColor; }
            set { descriptionColor = value; }
        }

        /// <summary>
        /// 描述字体
        /// </summary>
        [Category("6.描述文字显示设置"), Description("描述字体"), DisplayName("字体")]
        public Font DescriptionFont
        {
            get { return descriptionFont; }
            set
            {
                descriptionFont = value; descriotionPath = new GraphicsPath();
                descriotionPath.AddString(description, descriptionFont.FontFamily, (int)descriptionFont.Style, (Radius * descriptionFont.Size) / 60, new PointF(Width * descriptionPoint.X, Height * descriptionPoint.Y), SysConst.StringFormat_Center);
                Invalidate();
            }
        }

        /// <summary>
        /// 描述字体显示位置
        /// </summary>
        [Category("6.描述文字显示设置"), Description("描述字体显示位置"), DisplayName("显示位置")]
        [TypeConverter(typeof(PointFConvertor))]
        public PointF DescriptionPoint
        {
            get { return descriptionPoint; }
            set
            {
                descriptionPoint = value; descriotionPath = new GraphicsPath();
                descriotionPath.AddString(description, descriptionFont.FontFamily, (int)descriptionFont.Style, (Radius * descriptionFont.Size) / 60, new PointF(Width * descriptionPoint.X, Height * descriptionPoint.Y), SysConst.StringFormat_Center);
                Invalidate();
            }
        }

        /// <summary>
        /// 高报警值
        /// </summary>
        [Category("1.主要参数设置"), DisplayName("高报警值"), Description("高报警值")]
        public float HightAlarm
        {
            get { return hightAlarm; }
            set
            {
                if (value <= _max && value >= _min)
                {
                    hightAlarm = value;
                    Init();
                    Invalidate();
                }
            }
        }

        /// <summary>
        /// 低报警值
        /// </summary>
        [Category("1.主要参数设置"), DisplayName("低报警值"), Description("低报警值")]
        public float LowAlarm
        {
            get { return lowAlarm; }
            set
            {
                if (value <= _max && value >= _min)
                {
                    lowAlarm = value;
                    Init();
                    Invalidate();
                }
            }
        }

        /// <summary>
        /// 刻度线颜色
        /// </summary>
        [Category("3.1主刻度线设置"), Description("刻度线颜色"), DisplayName("刻度线颜色")]
        public Color MainTickColor
        {
            get { return mainTickColor; }
            set
            {
                mainTickColor = value;
                Invalidate();
            }
        }

        /// <summary>
        /// 刻度线个数
        /// </summary>
        [Category("3.1主刻度线设置"), Description("刻度线个数"), DisplayName("刻度线个数")]
        public int MainTickCount
        {
            get => mainTickcount;
            set
            {
                mainTickcount = value;
                Init();
                Invalidate();
            }
        }

        /// <summary>
        /// 刻度线长度:非固定值,是比例值
        /// </summary>
        [Category("3.1主刻度线设置"), Description("刻度线长度"), DisplayName("刻度线长度")]
        public float MainTickLegth
        {
            get => mainTickLegth;
            set
            {
                mainTickLegth = value; Init(); Invalidate();
            }
        }

        /// <summary>
        /// 主刻度线路径
        /// </summary>
        [Browsable(false)]
        public GraphicsPath MainTickPath
        {
            get { return mainTickPath; }
            set { mainTickPath = value; Invalidate(); }
        }

        /// <summary>
        /// 刻度线宽度
        /// </summary>
        [Category("3.1主刻度线设置"), Description("刻度线宽度"), DisplayName("刻度线宽度")]
        public int MainTickWidth
        {
            get => mainTickWidth;
            set
            {
                mainTickWidth = value; Invalidate();
            }
        }

        /// <summary>
        /// 最大值
        /// </summary>
        [Category("1.主要参数设置"), DisplayName("最大值"), Description("最大值")]
        public float Max
        {
            get { return _max; }
            set
            {
                if (_max != value && value > _min)
                {
                    _max = Math.Max(_value, value);
                    DegreesPerUnit = (Max - Min) / SweepAngle;
                    UnitPerDegrees = SweepAngle / (Max - Min);
                    Init();
                    Invalidate();
                }
            }
        }

        /// <summary>
        ///仪表位置,默认(0.5,0.5),表示在控件中心.取值范围(0-1):表示上下左右偏移多少比例
        /// </summary>
        [Category("1.主要参数设置"), Description("仪表位置,默认(0,0),表示在控件中点.取值范围(0-1):表示上下左右偏移多少比例"), DisplayName("仪表位置")]
        [TypeConverter(typeof(PointFConvertor))]
        public PointF MeterPosition
        {
            get => meterPosition;
            set
            {
                //  if (value. > 0 && value <= 1)
                // {
                meterPosition = value; Init(); Invalidate();
                // }
            }
        }

        /// <summary>
        /// 仪表半径:(0-1):表示占控件整体的比例
        /// </summary>
        [Category("1.主要参数设置"), Description("仪表半径:(0-1):表示占控件整体的比例"), DisplayName("仪表半径")]
        public float MeterRadius
        {
            get => meterRadius;
            set
            {
                if (value > 0 && value <= 1)
                {
                    meterRadius = value; Init(); Invalidate();
                }
            }
        }

        /// <summary>
        /// 最小值
        /// </summary>
        [Category("1.主要参数设置"), DisplayName("最小值"), Description("最小值")]
        public float Min
        {
            get { return _min; }
            set
            {
                if (_min != value && value < _max)
                {
                    _min = Math.Min(_value, value);
                    DegreesPerUnit = (Max - Min) / SweepAngle;
                    UnitPerDegrees = SweepAngle / (Max - Min);
                    NeedleAngle = GetAngelByValue(_value);

                    Init();
                    Invalidate();
                }
            }
        }

        /// <summary>
        /// 指针颜色
        /// </summary>
        [Category("4.指针设置"), Description("指针颜色"), DisplayName("指针颜色")]
        public Color NeedleColor
        {
            get { return needleColor; }
            set
            {
                needleColor = value;
                //Init();
                Invalidate();
            }
        }

        /// <summary>
        /// 指针高度,控制粗细的
        /// </summary>
        [Category("4.指针设置"), Description("指针高度"), DisplayName("指针高度")]
        public float NeedleHight
        {
            get { return needleHight; }
            set
            {
                needleHight = value;
                Init();
                Invalidate();
            }
        }

        /// <summary>
        /// 指针样式
        /// </summary>
        [Category("4.指针设置"), Description("指针样式"), DisplayName("指针样式")]
        public EnumStytle NeedleStytle
        {
            get { return needleStytle; }
            set
            {
                needleStytle = value;
                Init();
                Invalidate();
            }
        }

        /// <summary>
        /// 指针长度
        /// </summary>
        [Category("4.指针设置"), Description("指针长度"), DisplayName("指针长度")]
        public float NeedleWidth
        {
            get { return needleWidth; }
            set
            {
                needleWidth = value;
                Init();
                Invalidate();
            }
        }

        /// <summary>
        /// 控件的中心位置!
        /// </summary>
        [Browsable(false)]
        public PointF Point_Center
        {
            get { return point_Center; }
            set
            {
                point_Center = value;
            }
        }

        /// <summary>
        /// 控件的实际半径,通过MeterRadius属性更改这个值
        /// </summary>
        [Browsable(false)]
        public float Radius { get => radius; set => radius = value; }

        /// <summary>
        /// 刻度环颜色
        /// </summary>
        [Category("3.2副刻度线设置"), Description("刻度颜色"), DisplayName("刻度颜色")]
        public Color SecondTickColor
        {
            get { return secondTickColor; }
            set
            {
                secondTickColor = value;
                Invalidate();
            }
        }

        /// <summary>
        /// 刻度环个数
        /// </summary>
        [Category("3.2副刻度线设置"), Description("刻度个数"), DisplayName("刻度个数")]
        public int SecondTickCount
        {
            get => secondTickcount;
            set
            {
                secondTickcount = value;
                Init();
                Invalidate();
            }
        }

        /// <summary>
        /// 刻度环长度:非固定值,是比例值
        /// </summary>
        [Category("3.2副刻度线设置"), Description("刻度长度"), DisplayName("刻度长度")]
        public float SecondTickLegth
        {
            get => secondTickLegth;
            set
            {
                secondTickLegth = value; Init(); Invalidate();
            }
        }

        /// <summary>
        /// 刻度环路径
        /// </summary>
        [Browsable(false), Category("3.2副刻度线设置"), Description("刻度路径"), DisplayName("刻度路径")]
        public GraphicsPath SecondTickPath
        {
            get { return secondTickPath; }
            set { secondTickPath = value; Invalidate(); }
        }

        /// <summary>
        /// 刻度环宽度
        /// </summary>
        [Category("3.2副刻度线设置"), Description("刻度宽度"), DisplayName("刻度宽度")]
        public int SecondTickWidth
        {
            get => secondTickWidth;
            set
            {
                secondTickWidth = value; Invalidate();
            }
        }

        /// <summary>
        /// 表盘开始角度value > -360 && value < 360
        /// </summary>
        [Category("1.主要参数设置"), Description("刻度环开始角度value > -360 && value < 360"), DisplayName("开始角度")]
        public float StartAngle
        {
            get { return _StartAngle; }
            set
            {
                if (value > -360 && value < 360)
                {
                    _StartAngle = (value + 360) % 360;
                    EndAngle = Angel_0_360(StartAngle + SweepAngle);
                    NeedleAngle = GetAngelByValue(_value);

                    Init();
                    this.Invalidate();
                }
            }
        }

        /// <summary>
        /// 表盘扫描大小(单位 度°)(value > 0 && value <= 360)
        /// </summary>
        [Category("1.主要参数设置"), Description("刻度环扫描大小(value > 0 && value <= 360)"), DisplayName("表盘扫描角度")]
        public float SweepAngle
        {
            get { return _SweepAngle; }
            set
            {
                if (value > 0 && value <= 360)
                {
                    _SweepAngle = value;
                    DegreesPerUnit = (Max - Min) / SweepAngle;
                    UnitPerDegrees = SweepAngle / (Max - Min);
                    EndAngle = Angel_0_360(StartAngle + SweepAngle);
                    Init();
                    this.Invalidate();
                }
            }
        }

        /// <summary>
        /// 刻度颜色
        /// </summary>
        [Category("3.3第三刻度线设置"), Description("刻度颜色"), DisplayName("刻度颜色")]
        public Color ThirdTickColor
        {
            get { return thirdTickColor; }
            set
            {
                thirdTickColor = value;
                Invalidate();
            }
        }

        /// <summary>
        /// 刻度个数
        /// </summary>
        [Category("3.3第三刻度线设置"), Description("刻度个数"), DisplayName("刻度个数")]
        public int ThirdTickCount
        {
            get => thirdTickcount;
            set
            {
                thirdTickcount = value;
                Init();
                Invalidate();
            }
        }

        /// <summary>
        /// 刻度长度:非固定值,是比例值
        /// </summary>
        [Category("3.3第三刻度线设置"), Description("刻度长度"), DisplayName("刻度长度")]
        public float ThirdTickLegth
        {
            get => thirdTickLegth;
            set
            {
                thirdTickLegth = value; Init(); Invalidate();
            }
        }

        /// <summary>
        /// 刻度路径
        /// </summary>
        [Browsable(false), Category("3.3第三刻度线设置"), Description("刻度路径"), DisplayName("刻度路径")]
        public GraphicsPath ThirdTickPath
        {
            get { return thirdTickPath; }
            set { thirdTickPath = value; Invalidate(); }
        }

        /// <summary>
        /// 刻度宽度
        /// </summary>
        [Category("3.3第三刻度线设置"), Description("刻度宽度"), DisplayName("刻度宽度")]
        public int ThirdTickWidth
        {
            get => thirdTickWidth;
            set
            {
                thirdTickWidth = value; Init(); Invalidate();
            }
        }

        /// <summary>
        /// 保留几位小数
        /// </summary>
        [Category("3.4Value刻度线设置"), Description("保留几位小数"), DisplayName("保留几位小数")]
        public int TickNumberDecimalPointCount
        {
            get { return tickNumberDecimalPointCount; }
            set
            {
                if (value >= 0)
                {
                    tickNumberDecimalPointCount = value; Init(); Invalidate();
                }
            }
        }

        /// <summary>
        /// Forward:表示顺时针由小变大;Reversal:表示逆时针由大变小
        /// </summary>
        [Category("1.主要参数设置"), Description("True:表示顺时针由小变大;False:表示逆时针由大变小"), DisplayName("量程方向")]
        public bool TickNumberDirection
        {
            get { return tickNumberDirection; }
            set
            {
                tickNumberDirection = value;
                NeedleAngle = GetAngelByValue(_value);
                Init(); Invalidate();
            }
        }

        /// <summary>
        /// 刻度字体
        /// </summary>
        [Category("3.4Value刻度线设置"), Description("刻度字体"), DisplayName("刻度字体")]
        public Font TickNumberFont
        {
            get { return tickNumberFont; }
            set { tickNumberFont = value; Init(); Invalidate(); }
        }

        /// <summary>
        /// 数字刻度环的大小(0-1)
        /// </summary>
        [Category("3.4Value刻度线设置"), Description("数字刻度的位置"), DisplayName("数字刻度环的位置")]
        public float TickNumberSize
        {
            get { return tickNumberSize; }
            set { tickNumberSize = value; Init(); Invalidate(); }
        }

        /// <summary>
        ///Value刻度数值颜色
        /// </summary>
        [Category("3.4Value刻度线设置"), Description("颜色"), DisplayName("颜色")]
        public Color TickNumColor
        {
            get { return tickNumColor; }
            set { tickNumColor = value; Invalidate(); }
        }

        /// <summary>
        /// 刻度环Alarm颜色,一般警告
        /// </summary>
        [Category("2.外环设置"), Description("刻度环Alarm颜色,一般警告"), DisplayName("刻度环Alarm颜色")]
        public Color TickRingAlarmColor
        {
            get => tickRingAlarmColor;
            set
            {
                tickRingAlarmColor = value;
                Invalidate();
            }
        }

        //
        /// <summary>
        /// 刻度环正常颜色
        /// </summary>
        [Category("2.外环设置"), Description("刻度环正常颜色"), DisplayName("刻度环Norm颜色")]
        public Color TickRingColor
        {
            get { return tickRingColor; }
            set
            {
                tickRingColor = value;
                Invalidate();
            }
        }

        /// <summary>
        /// 刻度环个数
        /// </summary>
        [Category("2.外环设置"), Description("刻度环Error颜色,严重报警"), DisplayName("刻度环Error颜色")]
        public Color TickRingErrorColor
        {
            get => tickRingErrorColor;
            set
            {
                tickRingErrorColor = value;
                //  Init();
                Invalidate();
            }
        }

        /// <summary>
        /// 刻度环路径
        /// </summary>
        [Browsable(false), Category("2.外环设置"), Description("刻度环路径"), DisplayName("刻度环路径")]
        public GraphicsPath TickRingPath
        {
            get { return tickRingPath; }
            set { tickRingPath = value; Invalidate(); }
        }

        /// <summary>
        /// 刻度环是否显示
        /// </summary>
        [Category("2.外环设置"), Description("刻度环是否显示"), DisplayName("刻度环显示")]
        public bool TickRingShow
        {
            get => tickRingLegth;
            set
            {
                tickRingLegth = value; Init(); Invalidate();
            }
        }

        /// <summary>
        /// 刻度环宽度
        /// </summary>
        [Category("2.外环设置"), Description("刻度环宽度"), DisplayName("刻度环宽度")]
        public int TickRingWidth
        {
            get => tickRingWidth;
            set
            {
                tickRingWidth = value; Invalidate();
            }
        }

        /// <summary>
        /// 刻度线大小(0-1):表示占总尺寸的比例
        /// </summary>
        [Category("2.外环设置"), Description("刻度环大小"), DisplayName("刻度环大小")]
        public float TickSize
        {
            get { return tickSize; }
            set
            {
                if (value > 0 && value <= 1)
                {
                    tickSize = value;
                    Init();
                    Invalidate();
                }
            }
        }

        /// <summary>
        /// 当前值显示单位
        /// </summary>
        [Category("5.当前值显示设置"), Description("显示单位"), DisplayName("显示单位")]
        public string Unit
        {
            get { return unit; }
            set { unit = value; Init(); Invalidate(); }
        }

        //{
        //    get { return SweepAngle / (Max - Min); }
        //}

        /// <summary>
        /// 一单位等于多少度
        /// </summary>
        [Browsable(false)]
        public float UnitPerDegrees
        {
            get { return unitPerDegrees; }
            set
            {
                unitPerDegrees = value;
            }
        }

        /// <summary>
        /// 当前值
        /// </summary>
        [Category("1.主要参数设置"), DisplayName("当前值"), Description("当前值")]
        public float Value
        {
            get { return _value; }
            set
            {
                if (_value != value)
                {
                    if (value >= Max)
                    {
                        _value = Max;
                    }
                    else if (value <= Min)
                    {
                        _value = Min;
                    }
                    else
                    {
                        _value = value;
                    }
                    if (value > LowAlarm)
                    {
                        EventAlarm?.Invoke(value);
                    }
                    else if (value > HightAlarm)
                    {
                        EventError?.Invoke(value);
                    }
                    NeedleAngle = GetAngelByValue(_value);
                    ValuePath = new GraphicsPath();

                    ValuePath.AddString(Value.ToString("F" + (CurrentDecimalPlaces)) + "" + Unit, ValueFont.FontFamily, (int)ValueFont.Style, ((Radius * ValueFont.Size) / 50) + 1, Position_Value, SysConst.StringFormat_Center);

                    try
                    {
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(Radius.ToString());
                    }

                    Invalidate();
                }
            }
        }

        /// <summary>
        /// 当前值字体
        /// </summary>
        [Category("5.当前值显示设置"), Description("当前值字体"), DisplayName("当前值字体")]
        public Font ValueFont
        {
            get { return valueFont; }
            set { valueFont = value; Init(); Invalidate(); }
        }

        /// <summary>
        /// Value值显示的位置
        /// </summary>
        [Category("5.当前值显示设置"), Description("当前值位置,默认(0.5,0.6),表示在控件中心下方.取值范围(0-1):表示上下左右偏移多少比例"), DisplayName("当前值位置")]
        [TypeConverter(typeof(PointFConvertor))]
        public PointF ValuePositionOffset
        {
            get => valuePositionOffset;
            set
            {
                //  if (value. > 0 && value <= 1)
                // {
                valuePositionOffset = value; Init(); Invalidate();
                // }
            }
        }

        #endregion Properties

        #region Events

        /// <summary>
        /// 当前值超过警告线
        /// </summary>
        public event Action<float> EventAlarm;

        /// <summary>
        /// 当前值超过错误线
        /// </summary>
        public event Action<float> EventError;

        /// <summary>
        /// 手动更改值
        /// </summary>
        public event Action<float> EventManualValueChange;

        #endregion Events

        #region Methods

        /// <summary>
        /// 根据Value计算对应角度(0-360的方式)
        /// </summary>
        public float GetAngelByValue(float val)
        {
            var v = val - Min;
            var sw = v * UnitPerDegrees;
            var res = TickNumberDirection ? Angel_0_360(StartAngle + sw) : Angel_0_360(EndAngle - sw);
            return res;
        }

        public void Init()
        {
            //MeterRadius
            //这里更改centerpoint和r可以更改整体的布局和大小
            var c = new PointF(Width / 2, Height / 2);
            var rrr = Math.Min(Height, Width) / 2;
            Radius = rrr * MeterRadius;
            Point_Center = new PointF(Width * MeterPosition.X, Height * MeterPosition.Y);
            Position_Value = new PointF(Width * ValuePositionOffset.X, Height * ValuePositionOffset.Y); ;
            if (Radius == 0)
            {
                return;
            }
            MainTickPath = GetTickPath(Point_Center, Radius * TickSize, StartAngle, SweepAngle, MainTickLegth, MainTickCount);

            SecondTickPath = GetTickPath(Point_Center, Radius * TickSize, StartAngle, SweepAngle, SecondTickLegth, SecondTickCount * MainTickCount);

            ThirdTickPath = GetTickPath(Point_Center, Radius * TickSize, StartAngle, SweepAngle, ThirdTickLegth, ThirdTickCount * SecondTickCount * MainTickCount);

            TickRingPath = GetTickRingPath(Point_Center, Radius * TickSize, StartAngle, SweepAngle);

            tickNumberPath = GetTickNumberPath(Point_Center, Radius * TickNumberSize, StartAngle, SweepAngle, MainTickCount, TickNumberDirection);
            ValuePath = new GraphicsPath();
            ValuePath.AddString(Value.ToString("F" + (CurrentDecimalPlaces)) + "" + Unit, ValueFont.FontFamily, (int)ValueFont.Style, (Radius * ValueFont.Size) / 50, Position_Value, SysConst.StringFormat_Center);

            NeedlePath = Shapes.CreateNeedle(NeedleStytle, NeedleWidth * Radius, NeedleHight * Radius);
            Matrix m = new Matrix();
            m.Translate(Point_Center.X, Point_Center.Y);
            NeedlePath.Transform(m);

            descriotionPath = new GraphicsPath();
            descriotionPath.AddString(description, descriptionFont.FontFamily, (int)descriptionFont.Style, (Radius * descriptionFont.Size) / 60, new PointF(Width * descriptionPoint.X, Height * descriptionPoint.Y), SysConst.StringFormat_Center);
        }

        protected override void InitLayout()
        {
            base.InitLayout();
            Init();
            //this.Invalidate();
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);
            var g = pe.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            if (DesignMode)
            {
                // Init();
            }
            if (TickRingShow)
            {
                pen.Color = TickRingColor.Light(100); pen.Width = TickRingWidth * 8;
                g.DrawPath(pen, TickRingPath);//最下面阴影

                pen.Color = TickRingErrorColor;
                g.DrawArc(pen, new CircleF(Point_Center, TickSize * Radius), -GetAngelByValue(HightAlarm), TickNumberDirection ? -(Max - HightAlarm) * UnitPerDegrees : (Max - HightAlarm) * UnitPerDegrees);//错误报警圆环

                pen.Color = TickRingAlarmColor;
                g.DrawArc(pen, new CircleF(Point_Center, TickSize * Radius), -GetAngelByValue(LowAlarm), TickNumberDirection ? -(HightAlarm - LowAlarm) * UnitPerDegrees : (HightAlarm - LowAlarm) * UnitPerDegrees);//警告报警圆环

                pen.Color = TickRingColor; pen.Width = TickRingWidth;
                g.DrawPath(pen, TickRingPath);//圆弧
            }
            pen.Color = ThirdTickColor; pen.Width = ThirdTickWidth;
            g.DrawPath(pen, ThirdTickPath);

            pen.Color = SecondTickColor; pen.Width = SecondTickWidth;
            g.DrawPath(pen, SecondTickPath);

            pen.Color = MainTickColor; pen.Width = MainTickWidth;
            g.DrawPath(pen, MainTickPath);

            #region 刻度环圆弧

            pen.Color = NeedleColor; pen.Width = TickRingWidth * 2;
            g.DrawArc(pen, new CircleF(Point_Center, TickSize * Radius), -NeedleAngle, TickNumberDirection ? Angel_0_360(NeedleAngle - StartAngle) : -Angel_0_360(EndAngle - NeedleAngle));//实际值圆弧

            #endregion 刻度环圆弧

            #region 绘制指针和刻度

            pen.Color = CurrentValueColor; pen.Width = 1;

            g.FillPath(new SolidBrush(TickNumColor), tickNumberPath);

            var path = (GraphicsPath)NeedlePath.Clone();
            using (Matrix matrix = new Matrix())
            {
                matrix.RotateAt(-NeedleAngle, Point_Center);
                path.Transform(matrix);
            }

            g.FillPath(new SolidBrush(NeedleColor), path);

            #endregion 绘制指针和刻度

            #region 绘制Value

            //
            g.FillPath(new SolidBrush(pen.Color), ValuePath);

            #endregion 绘制Value

            #region 绘制描述文字

            g.FillPath(new SolidBrush(descriptionColor), descriotionPath);

            #endregion 绘制描述文字
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);

            Init();
        }

        protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
        {
            if (width < 100)
            {
                width = 100;
            }
            if (height < 100)
            {
                height = 100;
            }
            base.SetBoundsCore(x, y, width, height, specified);
        }

        /// <summary>
        /// 将角度统一换算为0-360°表示
        /// </summary>
        /// <param name="angel"></param>
        /// <returns></returns>
        private float Angel_0_360(float angel)
        {
            return (angel + 360) % 360;
        }

        private GraphicsPath GetTickNumberPath(PointF centerpoint, float TickNumberSize, float StartAngle, float SweepAngle, int Count, bool tickNumberDirection)
        {
            GraphicsPath path = new GraphicsPath();
            var derPerUnit = (Max - Min) / Count;
            CircleF circle_in = new CircleF(centerpoint, TickNumberSize);
            var interval = SweepAngle / Count;

            for (int i = 0; i <= Count; i++)
            {
                var p1 = circle_in.PointOnPath(StartAngle + interval * i);
                if (tickNumberDirection)//顺时针
                {
                    path.AddString((Min + i * derPerUnit).ToString("F" + TickNumberDecimalPointCount), TickNumberFont.FontFamily, (int)TickNumberFont.Style, (TickNumberSize * TickNumberFont.Size) / 60, p1, SysConst.StringFormat_Center);
                }
                else
                {
                    path.AddString((Max - i * derPerUnit).ToString("F" + TickNumberDecimalPointCount), TickNumberFont.FontFamily, (int)TickNumberFont.Style, (TickNumberSize * TickNumberFont.Size) / 60, p1, SysConst.StringFormat_Center);
                }
                path.StartFigure();
            }
            return path;
        }

        /// <summary>
        /// 获取刻度路径
        /// </summary>
        /// <param name="centerpoint"></param>
        /// <param name="TickRadius"></param>
        /// <param name="StartAngle"></param>
        /// <param name="SweepAngle"></param>
        /// <param name="Length"></param>
        /// <param name="Count"></param>
        /// <returns></returns>
        private GraphicsPath GetTickPath(PointF centerpoint, float TickRadius, float StartAngle, float SweepAngle, float Length, int Count)
        {
            GraphicsPath path = new GraphicsPath();
            CircleF circle_in = new CircleF(centerpoint, TickRadius);
            CircleF circle_out = new CircleF(centerpoint, TickRadius * (1 - Length));
            var interval = SweepAngle / Count;
            for (int i = 0; i <= Count; i++)
            {
                var p1 = circle_in.PointOnPath(StartAngle + interval * i);
                var p2 = circle_out.PointOnPath(StartAngle + interval * i);
                path.AddLine(p1, p2);
                path.StartFigure();
            }
            return path;
        }

        /// <summary>
        /// 获取刻度环路径
        /// </summary>
        /// <param name="centerpoint"></param>
        /// <param name="v"></param>
        /// <param name="startAngle"></param>
        /// <param name="sweepAngle"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private GraphicsPath GetTickRingPath(PointF centerpoint, float TickRadius, float StartAngle, float SweepAngle, Graphics g = null)
        {
            GraphicsPath path = new GraphicsPath();
            CircleF circle_in = new CircleF(centerpoint, TickRadius);
            var start = Angel_0_360(-StartAngle);
            var sweepangel = -SweepAngle;
            path.AddArc(circle_in, start, sweepangel);
            return path;
        }

        #endregion Methods
    }
}